package com.xagent.engine.utils;

import com.xagent.engine.hook.HookInfo;

import java.util.HashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class HookUtil {
    public static final String[] excludePackages = new String[]{"com.xagent"};


    /**
     * @param signature 方法描述符
     * @return 将传入的方法描述符规范化后返回
     */
    public static String standardizationSignature(String signature) {
        if (signature == null || "".equals(signature)) return "";
        StringBuilder stringBuilder = null;
        for (String part : signature.split(",")) {
            if (part.startsWith("(")) {
                stringBuilder = new StringBuilder();
                stringBuilder.append("(");
                part = part.replace("(", "");
            }

            if (part.contains("[]")) {
                stringBuilder.append("[L");
            } else stringBuilder.append("L");


            if (!part.endsWith(")")) {
                stringBuilder.append(part.replace("[]", "").replaceAll("\\.", "/"));
                stringBuilder.append(";");
            } else {
                stringBuilder.append(part.replace("[]", "").replaceAll("\\.", "/").replace(")", ""));
                stringBuilder.append(";)");
            }


        }
        return stringBuilder != null ? stringBuilder.toString() : "";
    }

    /**
     * @param signature 方法描述符
     * @return 将传入的方法描述符规范化后返回
     */
    public static String getDescriptorWithoutReturnType(String signature) {
        if (signature == null || "".equals(signature)) return "";
        Matcher matcher = Pattern.compile("([a-zA-Z\\.]*)(\\([a-zA-Z\\.;/\\[\\],]*\\))").matcher(signature); // 没匹配返回值
        if (matcher.find()) {
            signature = matcher.group(2);
        }

        return signature;
    }

    /**
     * 判断当前传入类、方法的Hook类型
     *
     * @return 返回值包括source propagate sink 以及null，返回null则说明没有被hook
     */
    public static String getHookType(HashMap<String, HashMap<String, HookInfo>> policyMap, String className, String methodNameWithDescriptor) {
        String type = "";

        for (String hookType : policyMap.keySet()) {
            if (policyMap.get(hookType).containsKey(className) && policyMap.get(hookType).get(className).isHook(methodNameWithDescriptor)) {
                if (!"".equals(type)) {
                    type = type + "|";
                } else type = hookType;
            }
        }
        if ("|".equals(type.substring(type.length()))) type = type.substring(0, type.length() - 1);
        if ("".equals(type)) type = null;
        return type;
    }

    /**
     * 判断是否为source
     */
    public static boolean isSource(HashMap<String, HashMap<String, HookInfo>> policyMap, String className, String methodNameWithDescriptor) {
        if (policyMap.get("source").get(className) == null) return false;
        if (policyMap.get("source").get(className).isHook(methodNameWithDescriptor)) return true;
        return false;
    }
    /**
     * 判断是否为propagate
     */
    public static boolean isPropagate(HashMap<String, HashMap<String, HookInfo>> policyMap, String className, String methodNameWithDescriptor) {
        if (policyMap.get("propagate").get(className) == null) return false;
        if (policyMap.get("propagate").get(className).isHook(methodNameWithDescriptor)) return true;
        return false;
    }
    /**
     * 判断是否为sink
     */
    public static boolean isSink(HashMap<String, HashMap<String, HookInfo>> policyMap, String className, String methodNameWithDescriptor) {
        if (policyMap.get("sink").get(className) == null) return false;
        if (policyMap.get("sink").get(className).isHook(methodNameWithDescriptor)) return true;
        return false;
    }

    /**
     * 暂时设定，一个hook点，只能是source propagate以及sink中的一个，不能同时为其中几个
     */
    public static HookInfo getHookInfo(HashMap<String, HashMap<String, HookInfo>> policyMap, String className, String methodNameWithDescriptor) {
        HookInfo hookInfo = null;
        for (String hookType : policyMap.keySet()) {
            if (policyMap.get(hookType).containsKey(className) && policyMap.get(hookType).get(className).isHook(methodNameWithDescriptor)) {
                return policyMap.get(hookType).get(className);
            }
        }

        return hookInfo;
    }
}
